#include <string>
#include <iostream>
#include <chrono>
#include <thread>

#include "../code/MysqlHandler.h"
#include "../code/DbConnPool.h"

// MysqlHandler 测试
void testMysqlHandler()
{
    std::cout << "\n=== MysqlHandler 测试 ===" << std::endl;
    bool res{};

    DbConnPool::MysqlHandler conn{};
    res = conn.connect("127.0.0.1", 3306, "root", "", "test");
    std::cout << "连接测试：" << res << std::endl;

    std::string sql = "INSERT INTO user(name) VALUES('li si')"; // 注意：未设置字符集用中文会失败
    res = conn.update(sql);
    std::cout << "DML 测试：" << res << std::endl;

    sql = "SELECT * FROM user";
    res = conn.query(sql);
    std::cout << "DQL 测试：" << res << std::endl;

    // 从结果集中取出一行
    std::cout << "每行字段值：" << std::endl;
    while (conn.next())
    {
        // 打印每行字段值
        std::cout << conn.getValue(0) << ", " << conn.getValue(1) << std::endl;
    }
}

// 单线程，DML，非连接池和连接池测试
void testPool1()
{
    std::cout << "\n=== 单线程, DML, 非连接池和连接池测试 ===" << std::endl;

    // 非连接池
    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

    for (int i = 0; i < 10000; ++i)
    {
        DbConnPool::MysqlHandler conn{};
        conn.connect("127.0.0.1", 3306, "root", "", "test");

        std::string sql = "INSERT INTO user(name) VALUES('" + std::to_string(i) + "')";
        conn.update(sql);
    }

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period = end - begin;
    std::cout << "非连接池用时: "
              << period.count() << " 纳秒, "
              << period.count() / 1000000 << " 毫秒"
              << std::endl;

    // 连接池
    DbConnPool::DbConnPool &pool = DbConnPool::DbConnPool::getInstance(std::string("/root/dbConnPool/test/conf.json"));

    std::chrono::steady_clock::time_point begin2 = std::chrono::steady_clock::now();

    for (int i = 0; i < 10000; ++i)
    {
        std::unique_ptr<DbConnPool::MysqlHandler, std::function<void(DbConnPool::MysqlHandler *)>> conn = pool.getConn();

        std::string sql = "INSERT INTO user(name) VALUES('" + std::to_string(i) + "')";
        conn->update(sql);
    }

    std::chrono::steady_clock::time_point end2 = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period2 = end2 - begin2;
    std::cout << "连接池用时: "
              << period2.count() << " 纳秒, "
              << period2.count() / 1000000 << " 毫秒"
              << std::endl;
}

// 单线程，DQL，非连接池和连接池测试
void testPool2()
{
    std::cout << "\n=== 单线程, DQL, 非连接池和连接池测试 ===" << std::endl;

    // 非连接池
    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

    for (int i = 0; i < 10000; ++i)
    {
        DbConnPool::MysqlHandler conn{};
        conn.connect("127.0.0.1", 3306, "root", "", "test");

        std::string sql = "SELECT * FROM user";
        conn.update(sql);
    }

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period = end - begin;
    std::cout << "非连接池用时: "
              << period.count() << " 纳秒, "
              << period.count() / 1000000 << " 毫秒"
              << std::endl;

    // 连接池
    DbConnPool::DbConnPool &pool = DbConnPool::DbConnPool::getInstance(std::string("/root/db/test/conf.json"));

    std::chrono::steady_clock::time_point begin2 = std::chrono::steady_clock::now();

    for (int i = 0; i < 10000; ++i)
    {
        std::unique_ptr<DbConnPool::MysqlHandler, std::function<void(DbConnPool::MysqlHandler *)>> conn = pool.getConn();

        std::string sql = "SELECT * FROM user";
        conn->update(sql);
    }

    std::chrono::steady_clock::time_point end2 = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period2 = end2 - begin2;
    std::cout << "连接池用时: "
              << period2.count() << " 纳秒, "
              << period2.count() / 1000000 << " 毫秒"
              << std::endl;
}

// 多线程，DML，非连接池和连接池测试
void testPool3()
{
    std::cout << "\n=== 多线程, DML, 非连接池和连接池测试 ===" << std::endl;

    // 非连接池
    auto dml = []()
    {
        for (int i = 0; i < 2000; ++i)
        {
            DbConnPool::MysqlHandler conn{};
            conn.connect("127.0.0.1", 3306, "root", "", "test");

            std::string sql = "INSERT INTO user(name) VALUES('" + std::to_string(i) + "')";
            conn.update(sql);
        }
    };

    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

    std::thread t1(dml);
    std::thread t2(dml);
    std::thread t3(dml);
    // std::thread t4(dml);
    // std::thread t5(dml);
    t1.join();
    t2.join();
    t3.join();
    // t4.join();
    // t5.join();

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period = end - begin;
    std::cout << "非连接池用时: "
              << period.count() << " 纳秒, "
              << period.count() / 1000000 << " 毫秒"
              << std::endl;

    // 连接池
    DbConnPool::DbConnPool &pool = DbConnPool::DbConnPool::getInstance(std::string("/root/db/test/conf.json"));

    // 注意引用捕获
    auto dml2 = [&pool]()
    {
        for (int i = 0; i < 2000; ++i)
        {
            std::unique_ptr<DbConnPool::MysqlHandler, std::function<void(DbConnPool::MysqlHandler *)>> conn = pool.getConn();

            std::string sql = "INSERT INTO user(name) VALUES('" + std::to_string(i) + "')";
            conn->update(sql);
        }
    };

    std::chrono::steady_clock::time_point begin2 = std::chrono::steady_clock::now();

    std::thread t6(dml2);
    std::thread t7(dml2);
    std::thread t8(dml2);
    // std::thread t9(dml2); // 多线程并发可能有 Segmentation fault
    // std::thread t10(dml2);
    t6.join();
    t7.join();
    t8.join();
    // t9.join();
    // t10.join();

    std::chrono::steady_clock::time_point end2 = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period2 = end2 - begin2;
    std::cout << "连接池用时: "
              << period2.count() << " 纳秒, "
              << period2.count() / 1000000 << " 毫秒"
              << std::endl;
}

// 多线程，DQL，非连接池和连接池测试
void testPool4()
{
    std::cout << "\n=== 多线程, DQL, 非连接池和连接池测试 ===" << std::endl;

    // 非连接池
    auto dml = []()
    {
        for (int i = 0; i < 2000; ++i)
        {
            DbConnPool::MysqlHandler conn{};
            conn.connect("127.0.0.1", 3306, "root", "", "test");

            std::string sql = "SELECT * FROM user";
            conn.update(sql);
        }
    };

    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

    std::thread t1(dml);
    std::thread t2(dml);
    std::thread t3(dml);
    // std::thread t4(dml);
    // std::thread t5(dml);
    t1.join();
    t2.join();
    t3.join();
    // t4.join();
    // t5.join();

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period = end - begin;
    std::cout << "非连接池用时: "
              << period.count() << " 纳秒, "
              << period.count() / 1000000 << " 毫秒"
              << std::endl;

    // 连接池
    DbConnPool::DbConnPool &pool = DbConnPool::DbConnPool::getInstance(std::string("/root/db/test/conf.json"));

    // 注意引用捕获
    auto dml2 = [&pool]()
    {
        for (int i = 0; i < 2000; ++i)
        {
            std::unique_ptr<DbConnPool::MysqlHandler, std::function<void(DbConnPool::MysqlHandler *)>> conn = pool.getConn();

            std::string sql = "SELECT * FROM user";
            conn->update(sql);
        }
    };

    std::chrono::steady_clock::time_point begin2 = std::chrono::steady_clock::now();

    std::thread t6(dml2);
    std::thread t7(dml2);
    std::thread t8(dml2);
    // std::thread t9(dml2); // 多线程并发可能有 Segmentation fault
    // std::thread t10(dml2);
    t6.join();
    t7.join();
    t8.join();
    // t9.join();
    // t10.join();

    std::chrono::steady_clock::time_point end2 = std::chrono::steady_clock::now();
    std::chrono::nanoseconds period2 = end2 - begin2;
    std::cout << "连接池用时: "
              << period2.count() << " 纳秒, "
              << period2.count() / 1000000 << " 毫秒"
              << std::endl;
}

int main()
{
    // MysqlHandler 测试
    // testMysqlHandler();

    // 单线程，DML，非连接池和连接池测试
    // testPool1();
    // 单/多线程，DML，非连接池和连接池测试，非连接池和连接池结果相近的可能原因：
    // 插入操作耗时久，累积后占耗时的大部分；本地连接数据库快；参数不合适；数据量少；服务端CPU核数环境等

    // 单线程，DQL，非连接池和连接池测试
    // testPool2();

    // 多线程，DML，非连接池和连接池测试
    // testPool3();

    // 多线程，DQL，非连接池和连接池测试
    testPool4();

    return 0;
}